#include "astralapi.h"
#include "queueapi.h"
#include "mapapi.h"
#include "strapi.h"
#include "device.h"

static struct HashMap devtable_ins;
static HashMap devtable = &devtable_ins;
DEFINE_QUEUE(devq);

boolean register_device(AstralDevice dev, AstralDevInfo info)
{
    boolean status = False;
    AstralDriver find_driver(u32 mid);
    AstralDriver driver = find_driver(info->mid);
    if (!driver)
    {
        kprint("can not find driver for \033[41m%s\033[0m, mid is %d.%d.%d.%d\n",
               info->name,
               MIDv4a(info->mid),
               MIDv4b(info->mid),
               MIDv4c(info->mid),
               MIDv4d(info->mid));
        return False;
    }
    else
    {
        kprint("-%6s mid is %d.%d.%d.%d \033[42monline\033[0m\n",
               info->name,
               MIDv4a(info->mid),
               MIDv4b(info->mid),
               MIDv4c(info->mid),
               MIDv4d(info->mid));
    }
    dev->operations = CAST_AS(object, driver);
    dev->vbase = dev->pbase = info->base;
    dev->irq = info->irq;
    strncpy(CAST_AS(char *, &dev->name), info->name, 10);

    HashNode hn = find_object_str(devtable, dev->name);
    if (hn)
    {
        return False;
    }
    hn = (HashNode)ff_alloc(sizeof(struct HashNode));
    if(!hn)
    {
        return False;
    }
    status = insert_object_str(devtable, hn,
                               dev->name,
                               CAST_AS(object, dev));
    queue_push(devq, &dev->reged);

    if(driver->dopen)
    {
        driver->dopen(dev, NULL);
    }

    return status;
}


void device_init()
{    
    void driver_manager_init();
    driver_manager_init();

    init_hashmap(devtable);
    
    extern struct AstralDevInfo __start_devtable;
    extern struct AstralDevInfo __stop_devtable;

    for(AstralDevInfo devif = &__start_devtable; devif < &__stop_devtable; devif++)
    {
        AstralDevice dev = (AstralDevice)ff_alloc(sizeof(struct AstralDevice));
        register_device(dev, devif);
    }
}


AstralDevice open_device(const char* name)
{
    HashNode hn = find_object_str(devtable, name);
    if(!hn)
    {
        return NULL;
    }
    return CAST_AS(AstralDevice, hn->value);
}

void list_device()
{
    QueueNode n = NULL;
    AstralDevice d = NULL;
    n = devq->first;
    while (n)
    {
        d = CONTAINER_OF(AstralDevice, reged, n);
        kprint("%10s %10s %s\n", d->name,
               d->operations->smid,
               d->operations->description);
        n = n->next;
    }
    
}